package runner;

import java.util.*;
import java.util.List;
import java.awt.*;



import main.*;
import view.*;
import model.*;
import interfaces.*;

/**
 * A simple predator-prey simulator, based on a rectangular field
 * containing rabbits and foxes.
 * 
 * @author David J. Barnes and Michael Kolling
 * @editor Stephan Veenstra, Marc Bruins, Michel Jansma
 * @version 2012.11.10
 */
public class SimulatorRunner {
    // Constants representing configuration information for the simulation.
    // The default width for the grid.
    public static final int DEFAULT_WIDTH = 50, 
    						DEFAULT_DEPTH = 50;
    // The probability that a fox will be created in any given grid position.
    private static final double FOX_CREATION_PROBABILITY    = 0.03,
    							RABBIT_CREATION_PROBABILITY = 0.08,
    							FALCON_CREATION_PROBABILITY = 0.06;
    
	// The probability that a Falcon will be created in any given grid position.
	private static final double TOTALHUNTERS = 15;
    
    
	private static PlaySound bgSound;
	public String musicFilePath = "./walk-of-life.mid";

    // List of animals in the field.
    public List<Actor> animals;
    // The current state of the field.
    private Field field;
    // The current step of the simulation.
    private int step;
    // A graphical view of the simulation.
    public Life life;
    
    public static void main(String[] args) {
    	new SimulatorRunner();
    }
    
    /**
     * Construct a simulation field with default size.
     */
    public SimulatorRunner() {
        this(DEFAULT_DEPTH, DEFAULT_WIDTH);
    }
    
    /**
     * Create a simulation field with the given size.
     * @param depth Depth of the field. Must be greater than zero.
     * @param width Width of the field. Must be greater than zero.
     */
    public SimulatorRunner(int depth, int width) {
    	
        if(width <= 0 || depth <= 0) {
            System.out.println("The dimensions must be greater than zero.");
            System.out.println("Using default values.");
            depth = DEFAULT_DEPTH;
            width = DEFAULT_WIDTH;
        }
        
        this.life 	 = new Life(this);
        this.animals = new ArrayList<Actor>();
        this.field   = new Field(depth, width);

        // Create a view of the state of each location in the field.
        this.life.getFieldView().setColor(Rabbit.class, Rabbit.COLOR);
        this.life.getFieldView().setColor(Fox.class,    Fox.COLOR);
        this.life.getFieldView().setColor(Falcon.class, Falcon.COLOR);
        this.life.getFieldView().setColor(Hunter.class, Hunter.COLOR);
		startSound(this.musicFilePath);
		this.reset();  
	}
    
    /**
     * Run the simulation from its current state for a reasonably long period,
     * e.g. 500 steps.
     */
    public void runLongSimulation() {
        this.simulate(500);
    }
    
    /**
     * Run the simulation from its current state for the given number of steps.
     * Stop before the given number of steps if it ceases to be viable.
     * @param numSteps The number of steps to run for.
     */
    public void simulate(int numSteps) {
        for(int step = 1; step <= numSteps && this.life.getFieldView().isViable(this.field); step++) {
            this.simulateOneStep();
        }
    }
    
    /**
     * Run the simulation from its current state for a single step.
     * Iterate over the whole field updating the state of each
     * fox and rabbit.
     */
    public void simulateOneStep() {
    	step++;
		
		//Provide space for newborn animals.
		List<Actor> newActors = new ArrayList<Actor>();

		// Let all rabbits act.
		for (Iterator<Actor> it = animals.iterator(); it.hasNext();) {
			Actor animal = it.next();
			animal.act(newActors);
			if (!animal.isActive()) {
				it.remove();
			}
		}

		// Add the newly born foxes and rabbits to the main lists.
		animals.addAll(newActors);

        //Update status
        this.updateStatus();
    }
        
    /**
     * Reset the simulation to a starting position.
     */
    public void reset() {
    	//Reset stel instantie variabele
        this.step = 0;
        //Leeg animals List
        this.animals.clear();
        //Generate animals
        this.populate();
    	populateHunters();
        //Update status
        this.updateStatus();        
    }
    
    private void updateStatus() {
    	//Update stappen
        this.life.getStepView().updateSteps(this.step);
        //Update fieldview
        this.life.getFieldView().showStatus(this.step, this.field);
        //Update populatie
        FieldStats stats = this.life.getFieldView().getStats();
        stats.updatePopulation(this.animals);
        //Update PieView
        this.life.getPieView().updatePopulation(stats.getPopulation(), stats.getTotalPopulation());
        //Update PieView
        this.life.getBarChartView().updatePopulation(stats.getPopulation(), stats.getTotalPopulation());
        //Update PopulationView
        this.life.getPopulationView().updatePopulation(stats.getPopulation(), stats.getTotalPopulation());
        //Repaint frame
        this.life.repaint();
    }
    
    /**
     * Randomly populate the field with foxes and rabbits.
     */
    private void populate() {
        Random rand = Randomizer.getRandom();
        field.clear();
        for(int row = 0; row < field.getDepth(); row++) {
            for(int col = 0; col < field.getWidth(); col++) {
                if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Fox fox = new Fox(true, this.field, location);
                    this.animals.add(fox);
                }
                else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Rabbit rabbit = new Rabbit(true, this.field, location);
                    this.animals.add(rabbit);
                }
                else if(rand.nextDouble() <= FALCON_CREATION_PROBABILITY){
                	Location location = new Location(row, col);
                	Falcon falcon = new Falcon(true, this.field, location);
                	this.animals.add(falcon);
                }
                // else leave the location empty.
            }
        }
    }
    /**
     * Populate the hunters
     */
	private void populateHunters() {
		Random rand = Randomizer.getRandom();
		for (int i = 0; i < TOTALHUNTERS; i++) {
			//GetRandomField
			int x = rand.nextInt(field.getDepth() + 1);
			int y = rand.nextInt(field.getWidth() + 1);
			if (x == 0) {x = x + 1;}
			if (y == 0) {y = y + 1;}
			
			Location location = new Location(x, y);
			Hunter hunter = new Hunter(field, location);
			animals.add(hunter);
		}
	}
	//Start the background sound
	public void startSound(String fileSrc){
		bgSound = new PlaySound(fileSrc);
		bgSound.startSound(true);
	}
	//Stop the background sound
	public void stopSound(){
		bgSound.stopSound();
	}
}


